1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.channel.handlercontext; 12 13 import std.conv; 14 import std.functional; 15 import kiss.logger; 16 import collie.channel.pipeline; 17 import collie.channel.handler; 18 import collie.channel.exception; 19 import collie.net; 20 import kiss.event.socket; 21 22 interface HandlerContext(In, Out) 23 { 24 alias HandlerTheCallBack = void delegate(Out, size_t); 25 26 void fireRead(In msg); 27 28 void fireTimeOut(); 29 30 void fireTransportActive(); 31 void fireTransportInactive(); 32 33 void fireWrite(Out msg, HandlerTheCallBack cback = null); 34 void fireClose(); 35 36 @property PipelineBase pipeline(); 37 38 @property Channel transport(); 39 40 } 41 42 interface InboundHandlerContext(In) 43 { 44 void fireRead(In msg); 45 void fireTimeOut(); 46 47 void fireTransportActive(); 48 void fireTransportInactive(); 49 50 @property PipelineBase pipeline(); 51 52 @property Channel transport(); 53 } 54 55 interface OutboundHandlerContext(Out) 56 { 57 alias OutboundTheCallBack = void delegate(Out, size_t); 58 59 void fireWrite(Out msg, OutboundTheCallBack cback = null); 60 void fireClose(); 61 62 @property PipelineBase pipeline(); 63 64 @property Channel transport(); 65 } 66 67 enum HandlerDir 68 { 69 IN, 70 OUT, 71 BOTH 72 } 73 74 class ContextImplBase(H, Context) : PipelineContext 75 { 76 ~this() 77 { 78 } 79 80 pragma(inline,true) 81 final @property auto handler() 82 { 83 return _handler; 84 } 85 86 pragma(inline,true) 87 final void initialize(PipelineBase pipeline, H handler) 88 { 89 _pipeline = pipeline; 90 _handler = handler; 91 } 92 93 // PipelineContext overrides 94 95 final override void attachPipeline() 96 { 97 if (!_attached) 98 { 99 attachContext(_handler, _impl); 100 _handler.attachPipeline(_impl); 101 _attached = true; 102 } 103 } 104 105 final override void detachPipeline() 106 { 107 _handler.detachPipeline(_impl); 108 _attached = false; 109 _pipeline = null; 110 } 111 112 final override void setNextIn(PipelineContext ctx) 113 { 114 if (!ctx) 115 { 116 _nextIn = null; 117 return; 118 } 119 auto nextIn = cast(InboundLink!(H.rout))(ctx); 120 if (nextIn) 121 { 122 _nextIn = nextIn; 123 } 124 else 125 { 126 throw new InBoundTypeException("inbound type mismatch after "); 127 } 128 } 129 130 final override void setNextOut(PipelineContext ctx) 131 { 132 if (!ctx) 133 { 134 _nextOut = null; 135 return; 136 } 137 auto nextOut = cast(OutboundLink!(H.wout))(ctx); 138 if (nextOut) 139 { 140 _nextOut = nextOut; 141 } 142 else 143 { 144 throw new OutBoundTypeException("outbound type mismatch after "); 145 } 146 } 147 148 pragma(inline) 149 final override HandlerDir getDirection() 150 { 151 return H.dir; 152 } 153 154 protected: 155 Context _impl; 156 PipelineBase _pipeline; 157 H _handler; 158 InboundLink!(H.rout) _nextIn = null; 159 OutboundLink!(H.wout) _nextOut = null; 160 161 private: 162 bool _attached = false; 163 } 164 165 mixin template CommonContextImpl() 166 { 167 alias Rin = H.rin; 168 alias Rout = H.rout; 169 alias Win = H.win; 170 alias Wout = H.wout; 171 172 this(PipelineBase pipeline, H handler) 173 { 174 _impl = this; 175 initialize(pipeline, handler); 176 } 177 178 // For StaticPipeline 179 this() 180 { 181 _impl = this; 182 } 183 184 pragma(inline) 185 final override @property Channel transport() 186 { 187 return _pipeline is null ? null : pipeline.transport(); 188 } 189 190 pragma(inline) 191 final override @property PipelineBase pipeline() 192 { 193 return _pipeline; 194 } 195 } 196 197 mixin template ReadContextImpl() 198 { 199 200 override void fireRead(Rout msg) 201 { 202 if (this._nextIn) 203 { 204 this._nextIn.read(msg); 205 } 206 else 207 { 208 logInfo("read reached end of pipeline"); 209 } 210 } 211 212 override void fireTimeOut() 213 { 214 if (this._nextIn) 215 { 216 this._nextIn.timeOut(); 217 } 218 } 219 220 override void fireTransportActive() 221 { 222 if (this._nextIn) 223 { 224 this._nextIn.transportActive(); 225 } 226 } 227 228 override void fireTransportInactive() 229 { 230 if (this._nextIn) 231 { 232 this._nextIn.transportInactive(); 233 } 234 } 235 236 // InboundLink overrides 237 override void read(Rin msg) 238 { 239 _handler.read(this, (msg)); 240 } 241 242 override void timeOut() 243 { 244 this._handler.timeOut(this); 245 } 246 247 override void transportActive() 248 { 249 this._handler.transportActive(this); 250 } 251 252 override void transportInactive() 253 { 254 _handler.transportInactive(this); 255 } 256 } 257 258 mixin template WriteContextImpl() 259 { 260 alias NextCallBack = void delegate(Wout, size_t); 261 262 pragma(inline) 263 override void fireWrite(Wout msg, NextCallBack cback = null) 264 { 265 if (_nextOut) 266 { 267 _nextOut.write(msg, cback); 268 } 269 else 270 { 271 logInfo("write reached end of pipeline"); 272 if(cback !is null) 273 cback(msg,0); 274 } 275 } 276 277 pragma(inline) 278 override void fireClose() 279 { 280 if (_nextOut) 281 { 282 _nextOut.close(); 283 } 284 else 285 { 286 logInfo("close reached end of pipeline"); 287 } 288 } 289 290 // OutboundLink overrides 291 alias ThisCallBack = void delegate(Win, size_t); 292 pragma(inline) 293 override void write(Win msg, ThisCallBack cback = null) 294 { 295 _handler.write(this, msg, cback); 296 } 297 298 pragma(inline) 299 override void close() 300 { 301 _handler.close(this); 302 } 303 304 } 305 306 final class ContextImpl(H) : ContextImplBase!(H, HandlerContext!(H.rout, 307 H.wout)), HandlerContext!(H.rout, H.wout), InboundLink!(H.rin), OutboundLink!(H.win) 308 { 309 310 static enum dir = HandlerDir.BOTH; 311 312 mixin CommonContextImpl; 313 314 mixin WriteContextImpl; 315 316 mixin ReadContextImpl; 317 318 } 319 320 final class InboundContextImpl(H) : ContextImplBase!(H, 321 InboundHandlerContext!(H.rout)), InboundHandlerContext!(H.rout), InboundLink!(H.rin) 322 { 323 static enum dir = HandlerDir.IN; 324 325 mixin CommonContextImpl; 326 327 mixin ReadContextImpl; 328 329 } 330 331 final class OutboundContextImpl(H) : ContextImplBase!(H, 332 OutboundHandlerContext!(H.wout)), OutboundHandlerContext!(H.wout), OutboundLink!(H.win) 333 { 334 335 static enum dir = HandlerDir.OUT; 336 337 mixin CommonContextImpl; 338 339 mixin WriteContextImpl; 340 } 341 342 template ContextType(H) 343 { 344 static if (H.dir == HandlerDir.BOTH) 345 alias ContextType = ContextImpl!(H); 346 else static if (H.dir == HandlerDir.IN) 347 alias ContextType = InboundContextImpl!(H); 348 else 349 alias ContextType = OutboundContextImpl!(H); 350 }